
package com.phm.phmneuron.generator;

import java.util.List;
import java.util.Objects;
import java.util.Random;

/**
 *
 * @author PARHAM
 */
public abstract class ArrayDataGenerator extends DataGenerator {
    protected List<float []> _arraySource = null;
    // the 0 index in "epoch" array keeps epoch value
    protected int [] _epoch = new int[1];
    protected int _epochValue = 1;
    
    
    public ArrayDataGenerator (List<float []> data, int epoch) {
        _arraySource = Objects.requireNonNull(data);
        _epochValue = epoch;
        _epoch = new int[data.size() + 1];
        for (int index = 0; index < _epoch.length; index++) {
            _epoch [index] = epoch;
        }
    }
    public ArrayDataGenerator (List<float []> data) {
        this (data, 1);
    }
    public List<float []> getDataSource () {
        return _arraySource;
    }
    
    // return -1 if there are no available index
    protected abstract int generateIndex ();
    
    @Override
    public void reset () {
        for (int index = 0; index < _epoch.length; index++) {
            _epoch [index] = _epochValue;
        }
        _numGeneratedSignals.set(0);
    }
    @Override
    protected float[] generate() {
        int gindex = generateIndex();
        if (gindex < 0) return null;
        _epoch [gindex]--;
        return _arraySource.get(gindex);
    }

    @Override
    public int countRemainSignals() {
        int remains = 0;
        for (int index = 0; index < _epoch.length; index++) {
            remains += _epoch [index];
        }
        return remains;
    }

    @Override
    public boolean hasMoreElement() {
        int g = countGeneratedSignals();
        int t = _epoch.length * _epochValue;
        if (g >= t) return false;
        return true;
    }
    
    public static class SequentialArrayDataGenerator extends ArrayDataGenerator {
        int seqIndex = 0;
        
        public SequentialArrayDataGenerator (List<float []> data, int epoch) {
            super (data, epoch);
        }
        public SequentialArrayDataGenerator (List<float []> data) {
            super (data);
        }
        
        @Override
        protected int generateIndex() {
            if (!this.hasMoreElement()) return -1;
            boolean done  = false;
            int result = 0;
            while (!done) {
                if (_epoch [seqIndex] > 0) {
                    result = seqIndex;
                    done = true;
                }
                seqIndex = seqIndex < (_epoch.length - 1) ? seqIndex + 1 : 0;
            }
            return result;
        }
    }
    public static class RandomArrayDataGenerator extends ArrayDataGenerator {
        
        protected Random rgen = new Random(System.currentTimeMillis());
        
        public RandomArrayDataGenerator (List<float []> data, int epoch) {
            super (data, epoch);
        }
        public RandomArrayDataGenerator (List<float []> data) {
            super (data);
        }

        @Override
        protected int generateIndex() {
            if (!hasMoreElement()) return -1;
            boolean done = false;
            int result = 0;
            while (!done) {
                result = rgen.nextInt(_epoch.length);
                if (_epoch [result] > 0) {
                    done = true;
                }
            }
            return result;
        }
    }
}
